#ifndef __LDX_CLIGHTMANAGER_H_INCLUDE__
#define __LDX_CLIGHTMANAGER_H_INCLUDE__
#include "LDXConfig.h"
#include "ISceneNode.h"
#include "DCBufferDefines.h"
#include "SDeviceMap.h"

namespace ldx
{
	namespace render
	{
		class CBufferObject;
	}
	namespace scene
	{
		enum E_LIGHT_MOVE_TYPE
		{
			ELMT_STATIC,//cannot move
			ELMT_DYNAMIC,//can move
		};
		class CLightSceneNode;
		class SLightsNeed
		{
		public:

			std::list<CLightSceneNode*> LightsNeed;
			~SLightsNeed()
			{
				LightsNeed.clear();
			}

			int getNum()
			{
				return (int)LightsNeed.size();
			}
		};

		class CLightsManager :public ISceneNode
		{
		public:
			CLightsManager(CSceneManager* mgr);

			~CLightsManager();

			CLightSceneNode* createLight(
				E_LIGHT_MOVE_TYPE type,
				ISceneNode* parent,
				int id = -1,
				mt::vec4f position = mt::vec4f(0, 0, 0, 1),
				mt::vec3f intensities = mt::vec3f(1, 1, 1),
				float attenuation = 0.f,
				float ambientCoefficient = 0.01f,
				float coneAngle = 180.f,
				mt::vec3f coneDirection = mt::vec3f(0, 0, 1));

			//! Build spot light
			CLightSceneNode* createSpotLightt(
				E_LIGHT_MOVE_TYPE type,
				ISceneNode* parent,
				int id = -1,
				mt::vec4f position = mt::vec4f(-1, -1, -1, 1),
				mt::vec3f  intensities = mt::vec3f(2, 2, 2),
				float attenuation = 0.1f,
				float ambientCoefficient = 0.06f);

			//! Build parallel light
			CLightSceneNode* createParalleLight(
				E_LIGHT_MOVE_TYPE type, 
				ISceneNode* parent,
				int id = -1,
				mt::vec4f position = mt::vec4f(-1.f, -1.f, -1.f, 0.f),
				mt::vec3f  intensities = mt::vec3f(0.3f, 0.3f, 0.3f),
				float ambientCoefficient = 0.06f);

			//! Build flash light.
			CLightSceneNode* createFlashLight(
				E_LIGHT_MOVE_TYPE type,
				ISceneNode* parent, 
				int id = -1,
				mt::vec4f position = mt::vec4f(-1, -1, -1, 1),
				mt::vec3f  intensities = mt::vec3f(2, 2, 2),
				float attenuation = 0.1f,
				float ambientCoefficient = 0.06f,
				float coneAngle = 15.0f,
				mt::vec3f coneDirection = mt::vec3f(0, 0, -1));

			const std::list<CLightSceneNode*>& getAllLights()const;

			//! get current lights based on positions of target and camera.
			void setCurrentLights(const mt::vec3f& targetPos,const mt::vec3f& cameraPos);

			//! Test is this light can be used.
			bool testLightused(const render::SLight* light,const mt::vec3f& targetPos, const mt::vec3f& cameraPos);

			//! Set Shader's buffer
			/** Warning! Please pay attention about the startslot value!
			* If types is: EST_VERTEXSHADER then call like this:
			*	setLightsConstantBuffers(EST_VERTEXSHADER,yourvsslot);
			* If types is: EST_PIXELSHADER then call like this:
			*	setLightsConstantBuffers(EST_PIXELSHADER,anyvalue,yourpsslot);
			* If types is: EST_VERTEXSHADER|EST_PIXELSHADER then call like this:
			*	setLightsConstantBuffers(EST_VERTEXSHADER|EST_PIXELSHADER,yourvsslot,yourpsslot);
			* ...
			*/
			bool setLightsConstantBuffers(uint types,
				mt::uint vsstartSlot = 0,
				mt::uint psstartSlot = 0, mt::uint gsstartSlot = 0);

		private:
			//! init global buffers.
			void initLocalBuffers();
			//! delete global buffers.
			void deleteLocalBuffers();
			//! update global buffers.
			void updateLocalBuffers();

			//! Insert a light into lists.
			void insertLight(CLightSceneNode* light, E_LIGHT_MOVE_TYPE type);
			SDeviceMap DM;
			std::list<CLightSceneNode*> ListLights;
			std::list<CLightSceneNode*> StaticLights;
			std::list<CLightSceneNode*> DynamicLights;

			std::list<const render::SLight*> CurrentLights;

			//buffer
			render::CBufferLights BufferLights;
			render::CBufferObject* BufferLightsObj;
		};
	}
}

#endif//! __LDX_CLIGHTMANAGER_H_INCLUDE__